package com.wan.core.strategy.selector;

import cn.hutool.log.StaticLog;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 可自定义规则的键值对策略选择器
 */
public final class StrategyCustomMapSelector<K, T> implements Selector<K, T> {

    private final Map<K, T> strategyMap = new ConcurrentHashMap<>();
    private Function<Collection<T>, T> chooseFunc;
    private T defaultStrategy;


    public StrategyCustomMapSelector(Collection<T> strategies, Function<T, K> generateKeyFunc) {
        strategyMap.putAll(strategies.stream().collect(Collectors.toMap(generateKeyFunc, t -> t)));
    }

    public StrategyCustomMapSelector(Collection<T> strategies, Consumer<Map<K, T>> consumer) {
        consumer.accept(strategyMap);
    }

    public StrategyCustomMapSelector(Function<Collection<T>, T> chooseFunc) {
        this.chooseFunc = chooseFunc;
    }

    public StrategyCustomMapSelector(Collection<T> strategies, Function<T, K> generateKeyFunc,Function<Collection<T>, T> chooseFunc) {
        this(strategies,generateKeyFunc);
        this.chooseFunc = chooseFunc;
    }


    public void setDefaultStrategy(T t) {
        this.defaultStrategy = t;
    }

    @Override
    public Optional<T> get(K k) {
        if (k == null) {
            try {
                if (chooseFunc == null) {
                    return Optional.ofNullable(defaultStrategy);
                }
                return Optional.of(chooseFunc.apply(strategyMap.values()));
            } catch (Exception e) {
                StaticLog.error(e,"choose error");
                return Optional.ofNullable(defaultStrategy);
            }
        }
        return Optional.ofNullable(strategyMap.getOrDefault(k, defaultStrategy));
    }

    @Override
    public Collection<T> getAll() {
        return strategyMap.values();
    }

    @Override
    public void add(K k, T t) {
        strategyMap.put(k, t);
    }

    @Override
    public void remove(K k, T t) {
        strategyMap.remove(k);
    }


}
